package index.btree;

import static storage.sql.Types.INTEGER;

import compiler.absyn.Constant;
import compiler.absyn.IntConstant;
import compiler.absyn.StringConstant;

import index.Index;
import storage.file.Block;
import storage.record.RID;
import storage.record.Schema;
import storage.record.TableInfo;
import storage.tx.Transaction;

public class BTreeIndex implements Index {
	private Transaction tx;
	private TableInfo dirmd, leafmd;
	private String dirfile, leaffile;
	private BTreeLeaf leaf = null;
	private Block rootblk;

	public BTreeIndex(int idxnumber, Schema leafsch, Transaction tx){
		this.tx = tx;
		leaffile = "leaf" + idxnumber + ".bt";
		leafmd = new TableInfo(leaffile, leafsch);
		if(tx.size(leaffile) == 0){
			tx.append(leaffile, new BTPageFormatter(leafmd, -1));
		}
		Schema dirsch = new Schema();
		dirsch.add("block", leafsch);
		dirsch.add("dataval", leafsch);
		dirfile = "dir" + idxnumber + ".bt";
		dirmd = new TableInfo(dirfile, dirsch);
		rootblk = new Block(dirfile, 0);
		if (tx.size(dirfile) == 0){
			tx.append(dirfile, new BTPageFormatter(dirmd, -1));
			BTreePage page = new BTreePage(rootblk, dirmd, tx);
			int fldtype = dirsch.type("dataval");
			Constant minval = (fldtype == INTEGER)?
					new IntConstant(Integer.MIN_VALUE):
					new StringConstant("");
			page.insertDir(0, minval, 0);
			page.close();
		}
	}
	
	@Override
	public void beforeFirst(Constant searchkey) {
		// TODO Auto-generated method stub
		close();
		BTreeDir root = new BTreeDir(rootblk, dirmd, tx);
		int blknum = root.search(searchkey);
		root.close();
		Block leafblk = new Block(leaffile, blknum);
		leaf = new BTreeLeaf(leafblk, leafmd, searchkey, tx);
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		if (leaf != null)
			leaf.close();
	}

	@Override
	public void delete(Constant dataval, RID rid) {
		// TODO Auto-generated method stub
		beforeFirst(dataval);
		leaf.delete(rid);
		leaf.close();
	}

	@Override
	public RID getDataRid() {
		// TODO Auto-generated method stub
		return leaf.getDataRid();
	}

	@Override
	public void insert(Constant dataval, RID rid) {
		// TODO Auto-generated method stub
		beforeFirst(dataval);
		DirEntry e = leaf.insert(rid);
		leaf.close();
		if (e == null)
			return;
		BTreeDir root = new BTreeDir(rootblk, dirmd, tx);
		e = root.insert(e);
		if (e != null)
			root.makeNewRoot(e);
		root.close();

	}

	@Override
	public boolean next() {
		// TODO Auto-generated method stub
		return leaf.next();
	}
	
	public static int searchCost(int numblocks, int rpb){
		return 1 + (int)(Math.log(numblocks) / Math.log(rpb));
	}

}
